﻿using System;
using System.Collections.Generic;

using System.Text;
using KNXObjects.Enum;



namespace KNXObjects.Addresses
{
    public class GroupAddressType : IEquatable<GroupAddressType>, IComparable<GroupAddressType>
    {
        #region Fields
        private ushort m_MainPart;
        private ushort m_MiddlePart;
        private ushort m_SecondaryPart;
        private GroupAddressTypeEnum m_Type = GroupAddressTypeEnum.ThreeLevels;
        private ushort m_Value = 0;
        #endregion

        #region Properties
        public GroupAddressTypeEnum Type
        {
            get { return m_Type; }
            set { m_Type = value; }
        }
        public ushort MainPart
        {
          get { return m_MainPart; }
          set { m_MainPart = value; }
        }
        public ushort MiddlePart
        {
            get { return m_MiddlePart; }
            set { m_MiddlePart = value; }
        }
        public ushort SecondaryPart
        {
            get { return m_SecondaryPart; }
            set { m_SecondaryPart = value; }
        }
        public ushort Value
        {
            get
            {
                if (m_Value == 0)
                {
                    if (Type == GroupAddressTypeEnum.ThreeLevels)
                        m_Value = Convert.ToUInt16(((MainPart & 0x01f) << 11) | ((MiddlePart & 0x07) << 8) | ((SecondaryPart & 0xff)));
                    else
                        m_Value = Convert.ToUInt16(((MainPart & 0x01f) << 11) | ((SecondaryPart & 0x7ff)));
                }

                return m_Value;
            }
        }
        #endregion

        #region Constructors
        public GroupAddressType(string readableAddress)
        {
            ExtractInfo(readableAddress);
        }

        public GroupAddressType(ushort binaryAddress)
        {
            ExtractInfo(binaryAddress);
            m_Value = binaryAddress;
        }

        #endregion

        #region Methods
        private void ExtractInfo(string readableAddress)
        {
            string[] parts = readableAddress.Split('/');
            if (parts.Length == 2)
            {
                this.Type = GroupAddressTypeEnum.TwoLevels;
                MainPart = Convert.ToUInt16(parts[0]);
                SecondaryPart = Convert.ToUInt16(parts[1]);
            }
            else if (parts.Length == 3)
            {
                this.Type = GroupAddressTypeEnum.ThreeLevels;
                MainPart = Convert.ToUInt16(parts[0]);
                MiddlePart = Convert.ToUInt16(parts[1]);
                SecondaryPart = Convert.ToUInt16(parts[2]);
            }          
        }

        private void ExtractInfo(ushort binaryAddress)
        {
            if (Type == GroupAddressTypeEnum.ThreeLevels)
            {
                MainPart = Convert.ToUInt16(binaryAddress >> 11);
                MiddlePart = Convert.ToUInt16((binaryAddress >> 8) & 0x07);
                SecondaryPart = Convert.ToUInt16(binaryAddress & 0xff);
            }
            else
            {
                MainPart = Convert.ToUInt16(binaryAddress >> 11);
                SecondaryPart = Convert.ToUInt16(binaryAddress & 0x7ff);
            }
        }

        public override string ToString()
        {
            if (Type == GroupAddressTypeEnum.ThreeLevels)
                return string.Format("{0}/{1}/{2}", MainPart, MiddlePart, SecondaryPart);
            else
                return string.Format("{0}/{1}", MainPart, SecondaryPart);
        }
        #endregion



        #region IEquatable<GroupAddress> Members

        public bool Equals(GroupAddressType other)
        {
            return Value.Equals(other.Value);
        }

        #endregion

        #region IComparable<GroupAddress> Members

        public int CompareTo(GroupAddressType other)
        {
            return Value.CompareTo(other.Value);
        }

        #endregion

        public static bool operator ==(GroupAddressType a, GroupAddressType b)
        {
            // If both are null, or both are same instance, return true.
            if (System.Object.ReferenceEquals(a, b))
            {
                return true;
            }

            // If one is null, but not both, return false.
            if (((object)a == null) || ((object)b == null))
            {
                return false;
            }

            // Return true if the fields match:
            return a.Value == b.Value && a.Value == b.Value && a.Value == b.Value;
        }

        public static bool operator !=(GroupAddressType a, GroupAddressType b)
        {
            return !(a == b);
        }

    }
}
